#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdint.h>
#include <string.h>

#include "od_thread.h"
#include "od_time.h"
#include "od_tube.h"
#include "od_os.h"
#include "od_trace.h"
#include "param_json.h"
#include "other2json.h"
#include "json_rpc.h"
#include "od_engine.h"
#include "od_framework.h"
#include "od_task.h"
#include "param_rpc.h"
#include "od_udp_send.h"


#include "console_param.h"
#include "sw_monitor.h"
#include "check_vid.h"
#include "ui_defines.h"
//#include "param_map.h"
#include "media.h"


#define SW_MONITOR_TSK_STACK_SIZE 64*1024

#define STREAM_TYPE_H265  0x24
#define STREAM_TYPE_H264  0x1B

#define V35_LOOPBACK_ON     0
#define V35_LOOPBACK_OFF    1

typedef enum{
    REMOTE_LOOPBACK_V35 = 0,
    REMOTE_LOOPBACK_UDP,
    REMOTE_LOOPBACK_NUMS,
}loopback_type;


#define SW_MONITOR_PARAM   "sw_monitor_param"
#define SW_MONITOR_NOTIFY  "sw_monitor.notify"

#define UDP_ADDR_STR_LEN 32

typedef struct sw_monitor_obj_s{
    OD_TASK_COMMON_MEMBERS

    sw_monitor_dynamic_params params_inside;
    int sw_monitor_id;
    int notify_id;
    int vdec_type;
    int vdec_detect_type;
    param_rpc_handle rpc_handle;
    od_msg_handle send_notify_msg_handle;
    int loopback_frame_detect;
    int loopback_status_change;
    int original_packet_type;
} sw_monitor_obj_t;

params_def_t sw_monitor_dynamic_params_def[] = 
{
    {OFFSET(sw_monitor_dynamic_params, loopback_ctrl), ODPT_VAR_INT32 | PT_REAL_TIME, sizeof(uint32_t), LOOPBACK_OFF, LOOPBACK_REMOTE_UDP},
    {0, 0, 0, 0, 0}
};

const sw_monitor_dynamic_params glb_sw_monitor_dynamic_params_default = 
{
    OD_OFF,
};

int send_notify_msg(void * hdl, char *param_name, int para_val)
{
    int ret = 0;
    char *temp = NULL;
    od_msg_t msg;
    struct json_object *jobj = NULL;
    struct json_object *jmulti_obj = NULL;
    struct json_object *rpc = NULL;
    int v_int = 0;
    int src_id = 0;
    int dst_id = 0;
    od_msg_handle msg_handle = NULL;
    sw_monitor_obj_t * sw_monitor_params = hdl;

    msg_handle = sw_monitor_params->send_notify_msg_handle;
    dst_id = sw_monitor_params->notify_id;
    src_id = sw_monitor_params->sw_monitor_id;

    v_int = (int)para_val;
    jobj = other2json_single_int(param_name, v_int);
    jmulti_obj = other2json_addpath(jobj, SW_MONITOR_PARAM);
    /*id = NULL, mean notify*/
    rpc = jsonrpc_request_pack(SW_MONITOR_NOTIFY, jmulti_obj, NULL);

    temp = (char *)od_calloc(1, strlen(json_object_get_string(rpc)) + 1);
    strncpy(temp, json_object_get_string(rpc), strlen(json_object_get_string(rpc)));
    msg.data_len = strlen(json_object_get_string(rpc)) + 1;
    msg.data = temp;
    msg.dst_id = dst_id;
    msg.src_id = src_id;
    ret = od_msg_send(msg_handle, &msg, 1000);
    RPTWRN("send src %d,dst %d, str:%s\n", src_id, dst_id, json_object_get_string(rpc));
    od_free(temp);
    json_object_put(rpc);

    return ret;
}

#if 0
static int send_notify_msg_ipaddr(void * hdl,  char *param_name, char *ipaddr)
{
    int ret = 0;
    char *temp = NULL;
    od_msg_t msg;
    struct json_object *jobj = NULL;
    struct json_object *jmulti_obj = NULL;
    struct json_object *rpc = NULL;
    char* vptr_str[2]={NULL, NULL};
    int src_id = 0;
    int dst_id = 0;
    od_msg_handle msg_handle = NULL;
    sw_monitor_obj_t * sw_monitor_params = hdl;

    msg_handle = sw_monitor_params->send_notify_msg_handle;
    dst_id = sw_monitor_params->notify_id;
    src_id = sw_monitor_params->sw_monitor_id;
    
    jobj = json_object_new_object();

    vptr_str[0] = ipaddr;
    ret = other2json_addstr(jobj, param_name, vptr_str, 1);
    if(0 > ret)
    {
        RPTERR("other2json_addstr ipaddr %s", vptr_str[0]);
        return OD_ERROR;
    }

    jmulti_obj = other2json_addpath(jobj, SW_MONITOR_PARAM);

    /*id = NULL, mean notify*/
    rpc = jsonrpc_request_pack(SW_MONITOR_NOTIFY, jmulti_obj, NULL);

    temp = (char *)od_calloc(1, strlen(json_object_get_string(rpc)) + 1);
    strncpy(temp, json_object_get_string(rpc), strlen(json_object_get_string(rpc)));
    msg.data_len = strlen(json_object_get_string(rpc)) + 1;
    msg.data = temp;
    msg.dst_id = dst_id;
    msg.src_id = src_id;
    ret = od_msg_send(msg_handle, &msg, 1000);
    RPTWRN("send src %d,dst %d, str:%s\n", src_id, dst_id, json_object_get_string(rpc));
    od_free(temp);
    json_object_put(rpc);

    return 0;
}
#endif

static int sw_monitor_start_stop( sw_monitor_obj_t * obj)
{
    RPTWRN("in");
    return 0;
}

static int sw_monitor_malloc_free( sw_monitor_obj_t * obj)
{
    RPTWRN("in");
    return 0;
}


static int sw_monitor_realtime_set(sw_monitor_obj_t * obj)
{
    return OD_OK;
}

static int sw_monitor_process(sw_monitor_obj_t * obj)
{
    od_msleep(1000);
    RPTERR("run loop!");
    return OD_OK;
}

static void sw_monitor_malloc_delete(sw_monitor_obj_t * obj)
{
    RPTDBG("in");
}

static void sw_monitor_start_stop_delete(sw_monitor_obj_t * obj)
{
    RPTDBG("in");
}

sw_monitor_handle sw_monitor_create(sw_monitor_static_params * static_params,
                                           sw_monitor_dynamic_params * dynamic_params)
{
    sw_monitor_obj_t * obj;
    sw_monitor_dynamic_params * params = NULL;

    if(static_params == NULL)
    {
        RPTERR(" (obj == NULL) NULL pointer");
        return NULL;
    }

    //alloc memory
    obj = od_task_create(static_params->tsk_name, sizeof(*obj));
    if(obj == NULL)
    {
        RPTERR(" sw_monitor_create NULL pointer");
        goto err2;
    }

    /*pass the rpc handle from static, and static pass from console obj*/
    obj->rpc_handle = static_params->rpc_handle;
    if( NULL == obj->rpc_handle)
    {
        RPTERR(" sw_monitor_create NULL pointer");
        goto err1;
    }

    obj->send_notify_msg_handle = od_msg_create_fix_trans(static_params->post_name, static_params->sw_monitor_id, MSG_MQ_PRIO_MIDDLE, 0);
    if( NULL == obj->send_notify_msg_handle)
    {
        RPTERR(" sw_msg_handle NULL pointer");
        goto err;
    }


    //param table init
    obj->tab = sw_monitor_dynamic_params_def;
    obj->params_nums = sizeof(sw_monitor_dynamic_params_def) / (sizeof(params_def_t)) - 1 ;
    params = od_calloc(1,sizeof(*params));
    if(NULL == params)
    {
        RPTERR(" create NULL pointer");
        goto err;
    }
    
    if(dynamic_params == NULL)
    {
        memcpy(params, &glb_sw_monitor_dynamic_params_default,sizeof(sw_monitor_dynamic_params)); 
    }
    else
    {
        memcpy(params,dynamic_params,sizeof(sw_monitor_dynamic_params)); 
    }
    obj->params = params;
    obj->stack_size = SW_MONITOR_TSK_STACK_SIZE;
    obj->pf_start_stop  = (void *)sw_monitor_start_stop;
    obj->pf_malloc_free = (void *)sw_monitor_malloc_free;
    obj->pf_process     = (void *)sw_monitor_process;
    obj->pf_malloc_free_delete = (void *)sw_monitor_malloc_delete;
    obj->pf_rt_set = (void *)sw_monitor_realtime_set;
    obj->pf_start_stop_delete = (void *)sw_monitor_start_stop_delete;

    obj->sw_monitor_id = static_params->sw_monitor_id;
    obj->notify_id = static_params->notify_id;
    obj->vdec_type = UI_VID_TYPE_H265;
    obj->vdec_detect_type = -1;//init -1 and start and will send msg when start

    obj->loopback_frame_detect = OD_ON;
    obj->loopback_status_change = LOOPBACK_OFF;

    return obj;

err:
    param_rpc_delete(obj->rpc_handle);
err1:
    od_task_delete(obj);
err2:
    return NULL;
}

